/*
 * @Author: shiguo
 * @Date: 2022-05-05 13:57:25
 * @LastEditors: shiguo
 * @LastEditTime: 2023-02-16 16:52:19
 * @FilePath: /@aks-dev/easyui/android/src/main/java/com/easyui/UpgradeModule.java
 */
package com.easyui;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;

import org.w3c.dom.Text;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;

public class UpgradeModule extends ReactContextBaseJavaModule {

    private ReactApplicationContext context;
    public static final int EXTERNAL_STORAGE_REQ_CODE = 10 ;
    private static Handler mHandler = new Handler(Looper.getMainLooper());
    private ProgressDialog mProgressDialog;
    private String mDownloadFile;


    private static void runOnMainThread(Runnable runnable) {
        mHandler.postDelayed(runnable, 0);
    }

    @NonNull
    @Override
    public String getName() {
        return "UpgradeModule";
    }


    public UpgradeModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.context = reactContext;

    }


    private String getAppVersionName() {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
            return info.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return "1.0.0";
        }
    }

    @ReactMethod
    public void getAppVersion(final Promise promise) {
        promise.resolve(this.getAppVersionName());
    }

    @ReactMethod
    public void getOSVersion(Promise promise) {
        promise.resolve(android.os.Build.VERSION.RELEASE);
    }


    @ReactMethod
    public void upgrade(final ReadableMap info, final Promise promise) {
        HashMap hashMap = info.toHashMap();
        String version = (String) hashMap.get("version");
        String title = (String) hashMap.get("title");
        String downloadUrl = (String) hashMap.get("downloadUrl");
        String note = (String) hashMap.get("note");
        Boolean force = (Boolean) hashMap.get("force");
        if (!checkUpdate(version, this.getAppVersionName())) {
            promise.reject("error_app_upgrade","已是最新版本");
            return ;
        }
        Activity currentActivity = context.getCurrentActivity();
        int permission = ActivityCompat.checkSelfPermission(context.getApplicationContext(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if (permission != PackageManager.PERMISSION_GRANTED) {
            // 请求权限
            ActivityCompat.requestPermissions(currentActivity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    EXTERNAL_STORAGE_REQ_CODE);
        }


        promise.resolve("发现新版本");
        runOnMainThread(new Runnable() {
            @Override
            public void run() {
                View view = View.inflate(currentActivity, R.layout.update_dialog, null);
                AlertDialog.Builder builder = new AlertDialog.Builder(currentActivity);
                builder.setView(view);
                if (force) {
                    builder.setCancelable(false);
                }
                final AlertDialog dialog = builder.show();

                WindowManager m = currentActivity.getWindowManager();
                WindowManager.LayoutParams p = dialog.getWindow().getAttributes();
                DisplayMetrics metrics = new DisplayMetrics();
                m.getDefaultDisplay().getMetrics(metrics);
                int widthPixels = metrics.widthPixels;
                p.width = (int) (widthPixels * 0.90);
                p.height = p.width * 780 / 680;


                dialog.getWindow().setAttributes(p);
                Window window = dialog.getWindow();
                window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

                TextView contentView = view.findViewById(R.id.content);
                Button confirmBtn = view.findViewById(R.id.btn_comfirm);
                Button cancelBtn = view.findViewById(R.id.btn_cancel);
                TextView titleView = view.findViewById(R.id.txt_title);

                contentView.setText(note);
                titleView.setText(title);
                confirmBtn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog.dismiss();
                        start(downloadUrl);
                    }
                });
                cancelBtn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (force) {
                            //android.os.Process.killProcess(android.os.Process.myPid());
                        } else {
                            dialog.dismiss();
                        }
                    }
                });
            }
        });


    }

    /**
     * 版本更新檢查
     *
     * @param remoteVersion
     * @param localVersion
     * @return true 需要更新 false 不需要更新
     */
    public boolean checkUpdate(String remoteVersion, String localVersion) {

        if (localVersion == null || localVersion.length() == 0 || remoteVersion == null || remoteVersion.length() == 0) {
            return false;
        }
        String[] localVers = localVersion.split("\\.");
        String[] remoteVers = remoteVersion.split("\\.");
        // 对比主版本
        if (compareVersion(localVers, remoteVers, 0) > 0) {
            return false;
        }
        if (compareVersion(localVers, remoteVers, 0) < 0) {
            return true;
        }
        // 对比子版本
        if (compareVersion(localVers, remoteVers, 1) > 0) {
            return false;
        }
        if (compareVersion(localVers, remoteVers, 1) < 0) {
            return true;
        }
        // 对比fix版本
        if (compareVersion(localVers, remoteVers, 2) < 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否需要更新
     *
     * @param localVers  本地版本
     * @param remoteVers 远程版本
     * @param idx        版本索引
     * @return
     */
    public int compareVersion(String[] localVers, String[] remoteVers, int idx) {
        if (remoteVers.length > idx && localVers.length <= idx) {
            return -1;
        }
        if (remoteVers.length <= idx && localVers.length > idx) {
            return 1;
        }
        if (remoteVers.length <= idx && localVers.length <= idx) {
            return 0;
        }
        Integer localVer = Integer.parseInt(localVers[idx]);
        Integer remoteVer = Integer.parseInt(remoteVers[idx]);
        return localVer.compareTo(remoteVer);
    }

    /**
     * 开始更新
     *
     * @param downloadUrl
     */
    public void start(String downloadUrl) {
        Activity currentActivity = context.getCurrentActivity();
        mProgressDialog = new ProgressDialog(currentActivity);
        mProgressDialog.setCanceledOnTouchOutside(false);
        mProgressDialog.setTitle("升级文件下载中，请稍候...");
        mProgressDialog.setIndeterminate(true);
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setCancelable(false);
        final DownloadTask downloadTask = new DownloadTask(currentActivity);
        downloadTask.execute(downloadUrl);
    }

    private void updateApk() {
        //安装应用
        Intent intent = new Intent(Intent.ACTION_VIEW);
        //sg
        ContextWrapper cw = new ContextWrapper(getReactApplicationContext());
        File directory = cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
        Activity currentActivity = context.getCurrentActivity();
        //判断是否是AndroidN以及更高的版本
        String packageName = context.getPackageName();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Uri contentUri = FileProvider.getUriForFile(currentActivity,packageName+".provider", new File(directory, mDownloadFile));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(contentUri,"application/vnd.android.package-archive");
        } else {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(Uri.fromFile(new File(directory, mDownloadFile)),
                    "application/vnd.android.package-archive");
        }
        currentActivity.startActivity(intent);
    }

    /**
     * 下载应用
     *
     * @author Administrator
     */
    class DownloadTask extends AsyncTask<String, Integer, String> {

        private Context context;
        private PowerManager.WakeLock mWakeLock;

        public DownloadTask(Context context) {
            this.context = context;
        }

        @Override
        protected String doInBackground(String... sUrl) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            File file = null;
            try {
                URL url = new URL(sUrl[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                // expect HTTP 200 OK, so we don't mistakenly save error
                // report
                // instead of the file
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    return "Server returned HTTP "
                            + connection.getResponseCode() + " "
                            + connection.getResponseMessage();
                }
                // this will be useful to display download percentage
                // might be -1: server did not report the length
                int fileLength = connection.getContentLength();

                mDownloadFile = "app_" + String.valueOf(System.currentTimeMillis()) + ".apk";
                //sg
                ContextWrapper cw = new ContextWrapper(getReactApplicationContext());
                File directory = cw.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
                file = new File(directory, mDownloadFile);
                //
                if (!file.exists()) {
                    // 判断父文件夹是否存在
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                }
                input = connection.getInputStream();
                output = new FileOutputStream(file);
                byte data[] = new byte[4096];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    // allow canceling with back button
                    if (isCancelled()) {
                        input.close();
                        return null;
                    }
                    total += count;
                    // publishing the progress....
                    if (fileLength > 0) // only if total length is known
                        publishProgress((int) (total * 100 / fileLength));
                    output.write(data, 0, count);

                }
            } catch (Exception e) {
                System.out.println(e.toString());
                return e.toString();

            } finally {
                try {
                    if (output != null)
                        output.close();
                    if (input != null)
                        input.close();
                } catch (IOException ignored) {
                }
                if (connection != null)
                    connection.disconnect();
            }
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            PowerManager pm = (PowerManager) context
                    .getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    getClass().getName());
            mWakeLock.acquire();
            mProgressDialog.show();
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            // if we get here, length is known, now set indeterminate to false
            mProgressDialog.setIndeterminate(false);
            mProgressDialog.setMax(100);
            mProgressDialog.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            mWakeLock.release();
            mProgressDialog.dismiss();
            if (result != null) {
                Toast.makeText(context, "您未打开SD卡权限" + result, Toast.LENGTH_LONG).show();
            } else {
                updateApk();
            }
        }
    }
}
